/*
 * Copyright 2011-2012 Rivoli team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.rivoli.builder

import com.googlecode.rivoli.Rivoli
import com.googlecode.rivoli.RivoliException
import com.googlecode.rivoli.configuration.Configurable
import com.googlecode.rivoli.configuration.Configuration
import com.googlecode.rivoli.model.Model
import com.googlecode.rivoli.reader.DefinitionReader
import com.googlecode.rivoli.writer.Writer

class Generator {
	private Configuration configuration

	String model
	String reader
	String name
	final Map<String, ?> data
	String writer
	OutputStream out

	private Generator() {
		data = [:]
	}

	// TODO convenience methods for adding data
	// TODO convenience methods for common output streams

	private void verifyComplete() throws RivoliException {
		if (!name) {
			throw new RivoliException('name is required')
		} else if (!out) {
			throw new RivoliException('output stream is required')
		}
	}

	private <T extends Configurable> T getConfigurable(Class<T> type, String name) throws RivoliException {
		Map<String, T> configurables = configuration.getConfigurables(type)

		String nameOfConfigurable = (name || (configurables.size() != 1)) ? name : configurables.keySet().iterator().next()

		if (configurables.containsKey(nameOfConfigurable)) {
			configurables[nameOfConfigurable]
		} else {
			throw new RivoliException("${type.simpleName.toLowerCase()} with name '${nameOfConfigurable}' not found in configuration")
		}
	}

	static void generate(Configuration configuration, Closure closure) throws RivoliException {
		Generator generator = new Generator(configuration: configuration)

		closure.delegate = generator
		closure.resolveStrategy = Closure.DELEGATE_FIRST
		closure()

		generator.verifyComplete()

		Model model = generator.getConfigurable(Model, generator.model)
		DefinitionReader reader = generator.getConfigurable(DefinitionReader, generator.reader)
		Writer writer = generator.getConfigurable(Writer, generator.writer)

		new Rivoli().generate(model, reader, generator.name, generator.data, writer, generator.out)
	}
}